package com.fy.fyspace.common.manager;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.*;
import com.fy.fyspace.common.config.AliOssConfig;
import com.fy.fyspace.common.utils.AliOssUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class OssManager {

    @Autowired
    private AliOssConfig aliOssConfig;

    @Resource
    private OSS ossClient;

    @Autowired
    private AliOssUtil aliOssUtil;

    // 用于存储分片上传状态
    private final Map<String, UploadStatus> uploadStatusMap = new ConcurrentHashMap<>();

    // 文件普通下载
    public InputStream getObject(String objectName) {
        return ossClient.getObject(aliOssConfig.getBucketName(), objectName).getObjectContent();
    }

    private static class UploadStatus {
        String uploadId;
        List<PartETag> partETags;
        Map<Integer, Boolean> uploadedParts;
        boolean isCompleted;

        UploadStatus(String uploadId, int totalParts) {
            this.uploadId = uploadId;
            this.partETags = new ArrayList<>(totalParts);
            this.uploadedParts = new HashMap<>(totalParts);
            this.isCompleted = false;
            
            // 初始化partETags列表
            for (int i = 0; i < totalParts; i++) {
                this.partETags.add(null);
                this.uploadedParts.put(i, false);
            }
        }

        synchronized void addPart(int index, PartETag partETag) {
            this.partETags.set(index, partETag);
            this.uploadedParts.put(index, true);
        }

        boolean isAllPartsUploaded() {
            return !uploadedParts.containsValue(false);
        }
    }

    /**
     * 上传并合并文件分片
     */
    public List<String> uploadAndMerge(byte[] chunk, String objectName, int index, int totalChunks,
                                     String uploadId, String newObjectName) {
        List<String> list = new ArrayList<>();
        String url;

        try {
            if (uploadId == null || uploadId.isEmpty()) {
                // 初始化分片上传
                InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(
                        aliOssConfig.getBucketName(), objectName);
                InitiateMultipartUploadResult initResult = ossClient.initiateMultipartUpload(initRequest);
                uploadId = initResult.getUploadId();
                log.info("uploadId为:{}", uploadId);
            }
            log.info("uploadId为:{}", uploadId);

            // 如果是最后一个分片，则合并所有分片
            if (index == totalChunks - 1) {
                // 上传分片
                uploadChunk(chunk, index, uploadId, objectName);
                url = mergeChunks(uploadId, totalChunks, objectName, newObjectName);
                list.add(null);
                list.add(url);
            } else if (index < totalChunks - 1) {
                uploadChunk(chunk, index, uploadId, objectName);
                list.add(uploadId);
                list.add(null);
            }
            log.info("返回的list:{}", list);
            return list;
        } catch (Exception e) {
            log.error("文件上传失败 - 文件: {}, 分片: {}/{}", objectName, index + 1, totalChunks, e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }

    private void uploadChunk(byte[] chunk, int index, String uploadId, String objectName) {
        UploadPartRequest uploadRequest = new UploadPartRequest();
        uploadRequest.setBucketName(aliOssConfig.getBucketName());
        uploadRequest.setKey(objectName);
        uploadRequest.setUploadId(uploadId);
        uploadRequest.setPartNumber(index + 1);
        uploadRequest.setInputStream(new ByteArrayInputStream(chunk));

        ossClient.uploadPart(uploadRequest);
    }

    private String mergeChunks(String uploadId, int totalChunks, String objectName, String newObjectName) {
        List<PartETag> partETags = getPartETags(uploadId, totalChunks, objectName);
        CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest(
                aliOssConfig.getBucketName(), objectName, uploadId, partETags);
        ossClient.completeMultipartUpload(completeRequest);

        // 重命名文件
        renameFile(objectName, newObjectName);

        return aliOssUtil.getFileUrl(newObjectName);
    }

    private void renameFile(String oldObjectName, String newObjectName) {
        // 复制文件到新名称
        CopyObjectRequest copyObjectRequest = new CopyObjectRequest(
                aliOssConfig.getBucketName(), oldObjectName,
                aliOssConfig.getBucketName(), newObjectName);
        ossClient.copyObject(copyObjectRequest);

        // 删除旧文件
        ossClient.deleteObject(aliOssConfig.getBucketName(), oldObjectName);
    }

    private List<PartETag> getPartETags(String uploadId, int totalChunks, String objectName) {
        ListPartsRequest listPartsRequest = new ListPartsRequest(
                aliOssConfig.getBucketName(), objectName, uploadId);
        PartListing partListing = ossClient.listParts(listPartsRequest);
        List<PartSummary> partSummaries = partListing.getParts();
        List<PartETag> partETags = new ArrayList<>();
        for (PartSummary partSummary : partSummaries) {
            partETags.add(new PartETag(partSummary.getPartNumber(), partSummary.getETag()));
        }
        return partETags;
    }

    /**
     * 普通文件上传
     */
    public String uploadFile(MultipartFile file) {
        // 生成新的文件名
        String newObjectName = generateNewFileName(file.getOriginalFilename());

        try (InputStream inputStream = file.getInputStream()) {
            // 上传文件到OSS
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    aliOssConfig.getBucketName(), newObjectName, inputStream);
            
            ossClient.putObject(putObjectRequest);
            log.info("文件上传成功，对象名: {}", newObjectName);

            // 获取文件的URL
            return aliOssUtil.getFileUrl(newObjectName);
        } catch (IOException e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }

    /**
     * 生成新文件名
     */
    private String generateNewFileName(String originalFileName) {
        long timestamp = System.currentTimeMillis();
        int dotIndex = originalFileName.lastIndexOf('.');
        String fileNameWithoutExtension = originalFileName.substring(0, dotIndex);
        String fileExtension = originalFileName.substring(dotIndex);
        return timestamp + "_" + fileNameWithoutExtension + fileExtension;
    }

    /**
     * 删除文件
     */
    public boolean deleteFile(String objectName) {
        try {
            aliOssUtil.delete(objectName);
            log.info("文件删除成功: {}", objectName);
            return true;
        } catch (Exception e) {
            log.error("文件删除失败: {}", objectName, e);
            return false;
        }
    }
} 